{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# OPTIMIZING MCX GATES - PREPARING FOR FUTURE HARDWARE TODAY\n",
    "\n",
    "This note describes how to use the Classiq platform to create MCX gates, including one with 14 controls. Then, it demonstrates a much more complex example with 50 control qubits."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## QUANTUM RESOURCES ARE VALUABLE, YET LIMITED\n",
    "\n",
    "Quantum computers offer tantalizing promises to those who can harness their power. And though today\u2019s computers are not quite able to solve real-world problems, those who are able to optimize for the hardware available will be able to reap rewards sooner than those who wait. The MCX gate is an important quantum gate used in a variety of circuits, such as the Grover Operator, logical AND operator, various state preparation algorithms, and arithmetic comparators. The ability to adapt implementations of MCX gates to meet the hardware constraints - limited qubit count, fidelities, gate count, and so on - is not trivial."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 1. HOW TO CREATE A 14-CONTROL MCX GATE WITH CLASSIQ\n",
    "\n",
    "To create an MCX gate with 14 control qubits using Classiq, we will first define a quantum function called `my_mcx`, whose arguments are an array of qubits (of any size) to be used as `control`, and a single qubit argument to be used as the `target`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:51.555401Z",
     "iopub.status.busy": "2024-05-07T13:29:51.555141Z",
     "iopub.status.idle": "2024-05-07T13:29:54.309599Z",
     "shell.execute_reply": "2024-05-07T13:29:54.308725Z"
    }
   },
   "outputs": [],
   "source": [
    "from math import pi\n",
    "\n",
    "from classiq import (\n",
    "    Constraints,\n",
    "    CustomHardwareSettings,\n",
    "    OptimizationParameter,\n",
    "    Output,\n",
    "    Preferences,\n",
    "    QArray,\n",
    "    QBit,\n",
    "    QuantumProgram,\n",
    "    X,\n",
    "    allocate,\n",
    "    control,\n",
    "    create_model,\n",
    "    qfunc,\n",
    "    set_constraints,\n",
    "    set_preferences,\n",
    "    show,\n",
    "    synthesize,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:54.315341Z",
     "iopub.status.busy": "2024-05-07T13:29:54.313790Z",
     "iopub.status.idle": "2024-05-07T13:29:54.319565Z",
     "shell.execute_reply": "2024-05-07T13:29:54.318870Z"
    }
   },
   "outputs": [],
   "source": [
    "@qfunc\n",
    "def my_mcx(cntrl: QArray[QBit], target: QBit) -> None:\n",
    "    control(cntrl, lambda: X(target))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, to create an MCX gate with 14 control qubits we will create a quantum `main` function that will simply execute our `my_mcx` function with 14 qubits allocated to the `control` argument.   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:54.324348Z",
     "iopub.status.busy": "2024-05-07T13:29:54.323282Z",
     "iopub.status.idle": "2024-05-07T13:29:54.328642Z",
     "shell.execute_reply": "2024-05-07T13:29:54.328089Z"
    }
   },
   "outputs": [],
   "source": [
    "@qfunc\n",
    "def main(cntrl: Output[QArray[QBit]], target: Output[QBit]) -> None:\n",
    "    allocate(14, cntrl)\n",
    "    allocate(1, target)\n",
    "    my_mcx(cntrl, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To build our model we will use the `create_model` function: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:54.332629Z",
     "iopub.status.busy": "2024-05-07T13:29:54.331600Z",
     "iopub.status.idle": "2024-05-07T13:29:54.344605Z",
     "shell.execute_reply": "2024-05-07T13:29:54.343935Z"
    }
   },
   "outputs": [],
   "source": [
    "model = create_model(main)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To constrain a circuit to only 20 qubits and optimize for circuit depth, we pass the max width and optimization parameter to a `Constraints` object and update our model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:54.349392Z",
     "iopub.status.busy": "2024-05-07T13:29:54.348230Z",
     "iopub.status.idle": "2024-05-07T13:29:54.364337Z",
     "shell.execute_reply": "2024-05-07T13:29:54.363633Z"
    }
   },
   "outputs": [],
   "source": [
    "from classiq import write_qmod\n",
    "\n",
    "constraints = Constraints(\n",
    "    max_width=20, optimization_parameter=OptimizationParameter.DEPTH\n",
    ")\n",
    "model = set_constraints(model, constraints)\n",
    "\n",
    "write_qmod(model, \"mcx_14_ctrl_depth\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now synthesize our model, create a quantum program and view it: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:54.369325Z",
     "iopub.status.busy": "2024-05-07T13:29:54.368149Z",
     "iopub.status.idle": "2024-05-07T13:29:59.958629Z",
     "shell.execute_reply": "2024-05-07T13:29:59.957948Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/f02def22-6d41-4874-b5d3-7dd2720bd13d?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "qprog = synthesize(model)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Additionally, To get the transpiled circuit from our `qprog` object and print its depth: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:29:59.999345Z",
     "iopub.status.busy": "2024-05-07T13:29:59.999036Z",
     "iopub.status.idle": "2024-05-07T13:30:00.016854Z",
     "shell.execute_reply": "2024-05-07T13:30:00.016035Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Synthesized MCX depth is 94\n"
     ]
    }
   ],
   "source": [
    "circuit = QuantumProgram.from_qprog(qprog)\n",
    "print(f\"Synthesized MCX depth is {circuit.transpiled_circuit.depth}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 2. AN MCX FOR EVERY OCCASION\n",
    "\n",
    "Classiq automatically optimizes the quantum circuit and each MCX gate to a plethora of possible situations. To characterize each setting we pass our constraints and preferences to the synthesis request using the `Constraints` and `Preferences` objects."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### 2.1 OPTIMIZING FOR DIFFERENT HARDWARE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:30:00.021288Z",
     "iopub.status.busy": "2024-05-07T13:30:00.020494Z",
     "iopub.status.idle": "2024-05-07T13:30:17.460879Z",
     "shell.execute_reply": "2024-05-07T13:30:17.460091Z"
    },
    "pycharm": {
     "is_executing": true,
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Synthesized MCX depth is 101\n",
      "Opening: https://platform.classiq.io/circuit/e45b46e1-1fd7-411f-88ba-615a3e6b4585?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "model = create_model(main)\n",
    "constraints = Constraints(\n",
    "    optimization_parameter=OptimizationParameter.DEPTH, max_width=21\n",
    ")\n",
    "preferences = Preferences(\n",
    "    backend_service_provider=\"IBM Quantum\", backend_name=\"ibmq_kolkata\"\n",
    ")\n",
    "model = set_constraints(model, constraints)\n",
    "model = set_preferences(model, preferences)\n",
    "\n",
    "write_qmod(model, \"mcx_14_ctrl_hardware\")\n",
    "\n",
    "\n",
    "qprog = synthesize(model)\n",
    "circuit = QuantumProgram.from_qprog(qprog)\n",
    "\n",
    "print(f\"Synthesized MCX depth is {circuit.transpiled_circuit.depth}\")\n",
    "circuit.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### 2.2 OPTIMIZING FOR CX GATES"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:30:17.470256Z",
     "iopub.status.busy": "2024-05-07T13:30:17.464322Z",
     "iopub.status.idle": "2024-05-07T13:30:22.838972Z",
     "shell.execute_reply": "2024-05-07T13:30:22.837789Z"
    },
    "pycharm": {
     "is_executing": true,
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Synthesized MCX cx-count is 168\n",
      "Opening: https://platform.classiq.io/circuit/c49dfb32-08c7-4d2f-a75b-f0dc9e1a5554?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "model = create_model(main)\n",
    "constraints = Constraints(max_width=19, optimization_parameter=\"cx\")\n",
    "preferences = Preferences(\n",
    "    custom_hardware_settings=CustomHardwareSettings(basis_gates=[\"cx\", \"u\"])\n",
    ")\n",
    "model = set_constraints(model, constraints)\n",
    "model = set_preferences(model, preferences)\n",
    "\n",
    "write_qmod(model, \"mcx_14_ctrl_cx\")\n",
    "\n",
    "\n",
    "qprog = synthesize(model)\n",
    "circuit = QuantumProgram.from_qprog(qprog)\n",
    "\n",
    "print(f\"Synthesized MCX cx-count is {circuit.transpiled_circuit.count_ops['cx']}\")\n",
    "circuit.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 3. BEYOND 14 CONTROLS\n",
    "\n",
    "The power of the Classiq synthesis engine is far greater than creating optimized, 14-control MCX gates in an instant. Take the following code, where we create an MCX gate with 50 control qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T13:30:22.843794Z",
     "iopub.status.busy": "2024-05-07T13:30:22.842584Z",
     "iopub.status.idle": "2024-05-07T13:30:40.321345Z",
     "shell.execute_reply": "2024-05-07T13:30:40.320441Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/6b3e2677-dd1d-4397-b40f-b6f15a2b61de?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "@qfunc\n",
    "def main(cntrl: Output[QArray[QBit]], target: Output[QBit]) -> None:\n",
    "    allocate(50, cntrl)\n",
    "    allocate(1, target)\n",
    "    my_mcx(cntrl, target)\n",
    "\n",
    "\n",
    "model = create_model(main)\n",
    "\n",
    "write_qmod(model, \"mcx_50_ctrl\")\n",
    "\n",
    "qprog = synthesize(model)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "![MCX depth](../../../resources/images/MCX_graph_1_dec_22.png)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
